#include "outils.h"
#include "Vue.h"
#include "Scene.h"
#include "Nourriture.h"
#include "Rattaupes.h"
#include "meoliste.h"
#include "Palmares.h"
#include "Reproduction.h"
#include "RegleDuJeu.h"
#include "Combat.h"
#include "sauvegarde.h"
#include "chargement.h"
#include "Race.h"

int main(void);
void main_init();
void difficulte(SDL_Surface* ecran);
void eEcrireNombreJoueur(SDL_Surface* ecran, int eDifficulte);
void Jouer(SDL_Surface* ecran, int32_t eNombreJoueur, int eDifficulte, int eChargement);
void TourSuivant(t_motte** pMotte, t_liste* pRattaupe, t_liste** pmatRattaupe, int32_t eNombreJoueurIncremente, int32_t eTour, int32_t eNombreJoueur, int eDifficulte, int* classement, SDL_Surface* ecran, SOCKET* csock, SOCKET* csockfin);
void Proposer_Quitter_findejeu (SDL_Surface* ecran);
void connection_client(int32_t eNombre_joueur, SOCKET* csock, SOCKET *csockfin, SDL_Surface* ecran, int eChargement);
void connection_pret(int32_t eNombre_joueur, SOCKET* csock);
void ChoisirRace(SDL_Surface* ecran, t_liste** pRattaupe);

int main(void){
	/* Fonction intialisant l'aléatoire et le main */
	Alea0();
	main_init();
	SDL_Quit();

	return EXIT_SUCCESS;
}

void main_init() {
	/* Fonction s'occupant du menu de départ, demande au joueur s'il veut quitter, lancer le jeu, charger la partie ou afficher les règles */
	SDL_Surface *ecran = NULL, *menu = NULL, *icone = NULL;
	SDL_Rect positionMenu;
	SDL_Event event;
	int continuer = 1;
	int eDifficulte = 0, eNombreJoueur = 0;

	SDL_Init(SDL_INIT_VIDEO);

	icone = IMG_Load("./images/icone.bmp");
	SDL_SetColorKey(icone, SDL_SRCCOLORKEY, SDL_MapRGB(icone->format, 62, 142, 171));
	SDL_WM_SetIcon(icone, NULL);
	SDL_FreeSurface(icone);

	ecran = SDL_SetVideoMode(LARGEUR_FENETRE, HAUTEUR_FENETRE+ESPACE_MENU, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
	SDL_WM_SetCaption("Koh-Lantaupe", NULL);

	menu = IMG_Load("./images/menu.jpg");
	positionMenu.x = 0;
	positionMenu.y = 0;

	SDL_BlitSurface(menu, NULL, ecran, &positionMenu);
	SDL_Flip(ecran);

	while (continuer)
	{
		SDL_BlitSurface(menu, NULL, ecran, &positionMenu);
		SDL_WaitEvent(&event);
		switch(event.type)
		{
			case SDL_QUIT:
				 SDL_FreeSurface(menu);
				 QuitterMenu();
				 break;
			case SDL_KEYDOWN:
				switch(event.key.keysym.sym)
				{
					case SDLK_ESCAPE: /* Veut arrêter le jeu */
						SDL_FreeSurface(menu);
						QuitterMenu();
						break;
					case SDLK_F1: /* Demande à jouer */
						SDL_FreeSurface(menu);
						difficulte(ecran);
						continuer=0;
						break;
					case SDLK_F2: /* Affiche les règles du jeu */
						init_RegleDuJeu(ecran);
						SDL_BlitSurface(menu, NULL, ecran, &positionMenu);
						SDL_Flip(ecran);
						break;
					case SDLK_F3: /* Charger le jeu */
						Jouer(ecran, eNombreJoueur, eDifficulte,1);
						break;
					default:
						break;
				}
			 break;
		}

	}
}

void difficulte(SDL_Surface* ecran){
	/* Fonction contenant un menu demandant au joueur de choisir la difficulté du jeu */
	SDL_Surface *menu = NULL;
	SDL_Event event;
	SDL_Rect positionMenu;
	int continuer = 1;

	menu = IMG_Load("./images/difficulte.jpg");
	positionMenu.x = 0;
	positionMenu.y = 0;

	SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0, 0, 0));
	SDL_BlitSurface(menu, NULL, ecran, &positionMenu);
	SDL_Flip(ecran);
	while (continuer)
	{
		SDL_WaitEvent(&event);
		switch(event.type)
		{
			case SDL_QUIT:
				SDL_FreeSurface(menu);
				QuitterMenu();
				break;
			case SDL_KEYDOWN:
				switch(event.key.keysym.sym)
				{
					case SDLK_ESCAPE:
						SDL_FreeSurface(menu);
						main_init();
						continuer=0;
						break;
					case SDLK_F1:
						SDL_FreeSurface(menu);
						eEcrireNombreJoueur(ecran,1);
						continuer=0;
						break;
					case SDLK_F2:
						SDL_FreeSurface(menu);
						eEcrireNombreJoueur(ecran,2);
						continuer=0;
						break;
					case SDLK_F3:
						SDL_FreeSurface(menu);
						eEcrireNombreJoueur(ecran,3);
						continuer=0;
						break;
					default:
						break;
				}
				break;
		}
	}
}

void eEcrireNombreJoueur(SDL_Surface* ecran, int eDifficulte){
	/* Fonction contenant un menu demandant au joueur de choisir le nombre de joueur de la partie */
	SDL_Surface *menu = NULL;
	SDL_Event event;
	SDL_Rect positionMenu;
	int continuer = 1;

	menu = IMG_Load("./images/joueurs.jpg");
	positionMenu.x = 0;
	positionMenu.y = 0;

	SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0, 0, 0));
	SDL_BlitSurface(menu, NULL, ecran, &positionMenu);
	SDL_Flip(ecran);

	while (continuer)
	{
		SDL_WaitEvent(&event);
		switch(event.type)
		{
			case SDL_QUIT:
				SDL_FreeSurface(menu);
				QuitterMenu();
				break;
			case SDL_KEYDOWN:
				switch(event.key.keysym.sym)
				{
					case SDLK_ESCAPE:
						SDL_FreeSurface(menu);
						difficulte(ecran);
						break;
					case SDLK_F2:
						SDL_FreeSurface(menu);
						Jouer(ecran,2,eDifficulte,0);
						continuer=0;
						break;
					case SDLK_F3:
						SDL_FreeSurface(menu);
						Jouer(ecran,3,eDifficulte,0);
						continuer=0;
						break;
					case SDLK_F4:
						SDL_FreeSurface(menu);
						Jouer(ecran,4,eDifficulte,0);
						continuer=0;
						break;
					default:
						break;
				}
			   break;
		}
	}
}

void Jouer (SDL_Surface* ecran, int32_t eNombreJoueur, int eDifficulte, int32_t eChargement){
	/* Fonction s'occupant d'appeler les principales fonctions d'initialisation du jeu et celle du changement de tour */
	int32_t eTour=0, eNombreJoueurIncremente;
	int eNombreJoueurIncrementeTour,eSocketIncremente;
	char sTour[50], sJoueur[100];
	int32_t eJeufin=htonl(1);
	int* classement=Palmares_init(eNombreJoueur);
	SDL_Surface *SDL_Texte = NULL, *SDL_Clean = NULL;
	t_motte** pMotte= Vue_init();
	t_liste** pRattaupe;

	SOCKET* csock=(SOCKET*)malloc(4*sizeof(SOCKET));
	SOCKET* csockfin=(SOCKET*)malloc(4*sizeof(SOCKET));

	Vue_bord(pMotte);

	for(eSocketIncremente=1;eSocketIncremente<4;eSocketIncremente++){
		csock[eSocketIncremente]=-1;
		csockfin[eSocketIncremente]=-1;
	}

	if(eChargement==1)
		pRattaupe = charger_amorcer(pMotte, &eDifficulte, &eNombreJoueur,&eTour);
	else {
		pRattaupe = Rattaupes_init(eNombreJoueur);
		Rattaupes_placer(pRattaupe, eNombreJoueur, pMotte);
		Vue_Rocher_placer(pMotte);
		ChoisirRace(ecran,pRattaupe);
	}

	connection_client(eNombreJoueur,csock,csockfin,ecran,eChargement);
	connection_pret(eNombreJoueur, csock);

	SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 255, 255, 255));
	Vue_afficher(pMotte,ecran);
	SDL_Flip(ecran);

	for(eNombreJoueurIncrementeTour=0;eNombreJoueurIncrementeTour<eNombreJoueur;eNombreJoueurIncrementeTour++){
		while(!liste_vide(pRattaupe[eNombreJoueurIncrementeTour])){
			sprintf(sTour, "Tour n°%i de Koh-Lantaupe !",eTour+1);
			SDL_Ecrire(ecran, SDL_Texte, sTour, 5, HAUTEUR_FENETRE+5);
			for(eNombreJoueurIncremente=0;eNombreJoueurIncremente<eNombreJoueur;eNombreJoueurIncremente++){
				if(!liste_vide(pRattaupe[eNombreJoueurIncremente])){
					if(eNombreJoueurIncremente==0){
						sprintf(sJoueur, "Joueur de l'équipe n°%i, à vous de jouer !",eNombreJoueurIncremente+1);
						SDL_Ecrire(ecran, SDL_Texte, sJoueur, 5, HAUTEUR_FENETRE+20);
						SDL_Flip(ecran);
					}
					else {
						SDL_Rect_Blanc(ecran,SDL_Clean, ESPACE_MENU-15, LARGEUR_FENETRE-5, 5, HAUTEUR_FENETRE+20); /* Menu */
						SDL_Rect_Blanc(ecran,SDL_Clean, 20, 85, LARGEUR_FENETRE-85, HAUTEUR_FENETRE); /* Santé */
						SDL_Flip(ecran);
					}
					TourSuivant(pMotte,pRattaupe[eNombreJoueurIncremente],pRattaupe,eNombreJoueurIncremente,eTour,eNombreJoueur,eDifficulte,classement,ecran,csock,csockfin);
				}
			}
			eTour++;
			Palmares_Incremente(pRattaupe, eNombreJoueur, classement);
		}
	}
	for(eNombreJoueurIncremente=1;eNombreJoueurIncremente<eNombreJoueur;eNombreJoueurIncremente++){
		send(csockfin[eNombreJoueurIncremente], (char const*)&eJeufin, sizeof(eJeufin), 0);
	}

	Palmares_Afficher (eNombreJoueur, classement, ecran, csockfin);
	Envoyer_tour(0,eNombreJoueur,csock);
	sleep(3);
	Quitter(eNombreJoueur,pMotte,pRattaupe,classement,csock,csockfin);
	Proposer_Quitter_findejeu(ecran);

}

void TourSuivant(t_motte** pMotte, t_liste* pRattaupe, t_liste** pmatRattaupe, int32_t eNombreJoueurIncremente, int32_t eTour, int32_t eNombreJoueur, int eDifficulte, int* classement, SDL_Surface* ecran, SOCKET* csock, SOCKET* csockfin){
	/* Définit les actions pour chaque tour */
	Envoyer_tour(1,eNombreJoueur,csock);
	if(eNombreJoueurIncremente==0){
		Save_amorcer(eDifficulte, eNombreJoueur, pMotte, pmatRattaupe,eTour);
		Nourriture_decremente(pMotte);
		Nourriture_init(pMotte,eTour,eDifficulte);
	}
	Sante_decremente(pRattaupe,eTour);
	Combat_init(eNombreJoueurIncremente,pMotte,eNombreJoueur,pmatRattaupe,csock,ecran,pMotte);
	Mort_Rattaupe(pMotte,pRattaupe,ecran,eNombreJoueurIncremente,eNombreJoueur,csock);
	Enceinte_incremente(pRattaupe,eTour);
	Reproduction_init(pRattaupe, pMotte,ecran,eNombreJoueurIncremente,eNombreJoueur,csock);
	Accouchement(pRattaupe,pMotte,ecran,eNombreJoueurIncremente,eNombreJoueur,csock);
	Rattaupe_Grandis(pRattaupe);
	Envoyer_pMotte(pMotte,eNombreJoueur,eNombreJoueurIncremente,eTour,csock);
	if(eNombreJoueurIncremente==0)
		Scene_Tour_Suivant(pRattaupe,pMotte,ecran,eNombreJoueur,pmatRattaupe,classement,csock,csockfin);
	else {
		Envoyer_pRattaupe(pRattaupe,eNombreJoueurIncremente,csock);
		Recevoir_pMotte(pMotte,eNombreJoueurIncremente,csock);
		Recevoir_pRattaupe(pRattaupe,eNombreJoueurIncremente,csock);
		usleep(100);
	}
}

void Proposer_Quitter_findejeu (SDL_Surface* ecran){
	/* Menu proposant de quitter au joueur à la fin du jeu ou de relancer une partie */
	SDL_Surface *menu = NULL;
	SDL_Event event;
	SDL_Rect positionMenu;
	int continuer = 1;

	menu = IMG_Load("./images/quitter.jpg");
	positionMenu.x = 0;
	positionMenu.y = 0;

	SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0, 0, 0));
	SDL_BlitSurface(menu, NULL, ecran, &positionMenu);
	SDL_Flip(ecran);
	while (continuer)
	{
		SDL_WaitEvent(&event);
		switch(event.type)
		{
			case SDL_QUIT:
				SDL_FreeSurface(menu);
				SDL_Quit();
				exit(EXIT_SUCCESS);
				break;
			case SDL_KEYDOWN:
				switch(event.key.keysym.sym)
				{
					case SDLK_F1:
						SDL_FreeSurface(menu);
						SDL_Quit();
						exit(EXIT_SUCCESS);
						break;
					case SDLK_F2:
						SDL_FreeSurface(menu);
						SDL_Quit();
						main_init();
						continuer=0;
						break;
					default:
						break;
				}
				break;
		}
	}
}

void connection_client(int32_t eNombre_joueur, SOCKET* csock, SOCKET *csockfin, SDL_Surface* ecran, int32_t eChargement){
	/* Permet de recevoir une connection pour un nombre de joueur précis sur 2 ports avec un pointeur de socket en paramètre pour enregistrer les connexions. Lit l'ip contenu dans le fichier config.txt et envoie au client son numéro de joueur et si la partie a été chargée ou pas */

	#if defined (WIN32)
		WSADATA WSAData;
		int erreur = WSAStartup(MAKEWORD(2,2), &WSAData);
	#else
		int erreur = 0;
	#endif

	SOCKET sock, sockfin;
	SOCKADDR_IN sin, csin;
	SOCKADDR_IN sinfin, csinfin;
	socklen_t recsize = sizeof(csin), recsizefin = sizeof(csinfin);
	int sock_err, sockfin_err;

	int32_t eSocketincremente, eNumJoueur;
	FILE* config;
	char sIpConfig[15];
	SDL_Surface *Connec = NULL;
	SDL_Rect positionConnec;

	Connec = IMG_Load("./images/co_client.jpg");
	positionConnec.x = 0;
	positionConnec.y = 0;

	config = fopen("config.txt", "r"); /* Créer le fichier en permission écriture */

	if (config != NULL){
		while(!feof(config)){
			fscanf(config, "%s", sIpConfig);
		}
	}

	fclose(config);

	if(erreur) { printf("Erreur des sockets windows"); exit(1); }

	sock = socket(AF_INET, SOCK_STREAM, 0);
	sockfin = socket(AF_INET, SOCK_STREAM, 0);

	SDL_BlitSurface(Connec, NULL, ecran, &positionConnec);
	SDL_Flip(ecran);

	/* Si la socket est valide */
	if(sock != INVALID_SOCKET&&sockfin != INVALID_SOCKET)
	{

		/* Configuration */
		sin.sin_addr.s_addr    = inet_addr(sIpConfig);   /* Adresse IP automatique */
		sin.sin_family         = AF_INET;             /* Protocole familial (IP) */
		sin.sin_port           = htons(11123);         /* Listage du port */
		sock_err = bind(sock, (SOCKADDR*)&sin, sizeof(sin));

		sinfin.sin_addr.s_addr    = inet_addr(sIpConfig);   /* Adresse IP automatique */
		sinfin.sin_family         = AF_INET;             /* Protocole familial (IP) */
		sinfin.sin_port           = htons(11134);         /* Listage du port */
		sockfin_err = bind(sockfin, (SOCKADDR*)&sinfin, sizeof(sinfin));

		/* Si la socket fonctionne */
		if(sock_err != SOCKET_ERROR&&sockfin_err != SOCKET_ERROR)
		{
			/* Démarrage du listage (mode server) */
			sock_err = listen(sock, eNombre_joueur);
			sock_err = listen(sockfin, eNombre_joueur);

			for(eSocketincremente=1;eSocketincremente<eNombre_joueur;eSocketincremente++){

				/* Si la socket fonctionne */
				if(sock_err != SOCKET_ERROR&&sockfin_err != SOCKET_ERROR)
				{
					/* Attente pendant laquelle le client se connecte */
					csock[eSocketincremente] = accept(sock, (SOCKADDR*)&csin, &recsize);
					csockfin[eSocketincremente] = accept(sockfin, (SOCKADDR*)&csinfin, &recsizefin);
					/* On envoie au joueur son numéro de joueur */
					eNumJoueur = htonl(eSocketincremente);
					eChargement = htonl(eChargement);
					send(csock[eSocketincremente], (char const*)&eNumJoueur, sizeof(eNumJoueur), 0);
					send(csock[eSocketincremente], (char const*)&eChargement, sizeof(eChargement), 0);
				}
			}
		}
	}
}

void connection_pret(int32_t eNombre_joueur, SOCKET* csock){
	/* Attend que tout les joueurs de la partie indiquent qu'ils sont prêt pour lancer le jeu */
	int32_t eJoueurincremente;
	int32_t reception = 0;
	for(eJoueurincremente=1;eJoueurincremente<eNombre_joueur;eJoueurincremente++){
		recv(csock[eJoueurincremente], (char *)&reception, sizeof(reception), 0);
		reception=ntohl(reception);
	}
}

void ChoisirRace(SDL_Surface* ecran, t_liste** pRattaupe){
	/* Menu demandant au joueur de choisir sa race */
	SDL_Surface *menu = NULL;
	SDL_Event event;
	SDL_Rect positionMenu;
	int continuer = 1;

	menu = IMG_Load("./images/Race.jpg");
	positionMenu.x = 0;
	positionMenu.y = 0;

	SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 161, 161, 160));
	SDL_BlitSurface(menu, NULL, ecran, &positionMenu);
	SDL_Flip(ecran);


	while (continuer)
	{
		SDL_WaitEvent(&event);
		switch(event.type)
		{
			case SDL_QUIT:
				SDL_FreeSurface(menu);
				QuitterMenu();
				break;
			case SDL_KEYDOWN:
				switch(event.key.keysym.sym)
				{
				case SDLK_ESCAPE:
					break;
				case SDLK_F1:
					SDL_FreeSurface(menu);
					InitialisationRace(Reproducteur, pRattaupe);
					continuer = 0;
					break;
				case SDLK_F2:
					SDL_FreeSurface(menu);
					InitialisationRace(Guerrier, pRattaupe);
					continuer = 0;
					break;
				case SDLK_F3:
					SDL_FreeSurface(menu);
					InitialisationRace(Defenseur, pRattaupe);
					continuer = 0;
					break;
				case SDLK_F4:
					SDL_FreeSurface(menu);
					InitialisationRace(Cuisinier, pRattaupe);
					continuer = 0;
					break;
				default:
					break;
				}
			   break;
		}
	}
}
